package main


import (
	"encoding/json"
	"fmt"
	"github.com/aceld/zinx/tool"
	"github.com/aceld/zinx/utils"
	"github.com/aceld/zinx/ziface"
	"github.com/aceld/zinx/zinx_akr_service/core"
	"github.com/aceld/zinx/zinx_modbus_tcp/api"
	dbutil "github.com/aceld/zinx/zinx_modbus_tcp/dao"
	log "github.com/cihub/seelog"
	"os"
	"time"

	//"github.com/aceld/zinx/zlog"
	"github.com/aceld/zinx/znet"
)





//当客户端建立链接的时候的hook函数
func OnConnectionAdd(conn ziface.IConnection)  {

	conn.SetProperty("askType",0)
	conn.SetProperty("lastTime",time.Now())

}

//当客户端断开连接的时候的hook函数
func OnConnectionLost(conn ziface.IConnection){

	device := core.DevicesMgrObj.GetDeviceByConn(conn)
	if device !=nil{
		if device.Status !=5{
			core.DevicesMgrObj.SetStatusByPID(device.PID,2)
			log.Debugf("%s设备离线",device.PID)
			tool.UpdateDeviceStatus(device.PID,2)//离线
		}
	}

}

func SetupLogger() error {
	//dir,_ := os.Getwd()
	//kv := strings.Split(dir, "\\")
	//var parentDir string
	//if len(kv)!=0{
	//	i := 0
	//	for ;i<(len(kv)-1);i++{
	//		parentDir=parentDir+kv[i]+"\\"
	//	}
	//}
	dir,_ := os.Getwd()
	fmt.Println(dir)
	logger, err := log.LoggerFromConfigAsFile("./config/zinx_modbus_tcp.xml")
	if err != nil {
		return err
	}
	log.ReplaceLogger(logger)
	return err
}




func storageDatToMysqlById(devuuid string,pointTypes []string,protocol string)  {

	dateTime := time.Now().Format("2006-01-02 15:04:05")

	rs := []rune(devuuid)

	sitSid := string(rs[0:14])

	for _,pointType := range pointTypes{

		reply,err := dbutil.HashGet(utils.DEVICE_TYPE_INFO+protocol,pointType)
		if err !=nil{
			log.Infof("设备查询失败或未同步到redis")
			continue
		}



		meterPointInfo := &api.MeterPointInfo{}
		err =json.Unmarshal([]byte(reply), &meterPointInfo)
		if err!=nil{
			log.Info("json反序列化失败")
			continue
		}
		if meterPointInfo.TabName == "iims_data_cache"{

				currentValue,err := dbutil.StringGetFloat(utils.DEVICES_VALUE_STRING+":"+devuuid+":"+pointType)
				if err !=nil{
					log.Infof("%v-%v 获取测点值失败",devuuid,pointType)
					continue
				}

				dbutil.StorageDatacacheToMysql(devuuid,pointType,currentValue,sitSid,dateTime)
		}

	}

}

func storageDataToMysql(){

	devices := dbutil.HashGetKeys(utils.DEVICES_STATUS_HASH)

	for _,devuuid :=range devices{
		meterLastInfo,err:=dbutil.HashGet(utils.DEVICES_STATUS_HASH,devuuid)
		if err !=nil{
			log.Infof("未找到设备:%v",devuuid)
			return
		}

		meterLastStatus := &api.MeterStatus{}
		err =json.Unmarshal([]byte(meterLastInfo), &meterLastStatus)
		if err!=nil{
			log.Info("json反序列化失败")
			continue
		}else{
			if meterLastStatus.Status == 1|| meterLastStatus.Status == 4{

				pointTypes := dbutil.HashGetKeys(utils.DEVICE_TYPE_INFO+meterLastStatus.Protocol)

				storageDatToMysqlById(devuuid,pointTypes,meterLastStatus.Protocol)
			}
		}
	}
}

func checkDevicesTimeOut(){


	//	checkCustomAlarm("A5012104300008C93002","10201",60.0)//测试用

	devices := dbutil.HashGetKeys(utils.DEVICES_STATUS_HASH)
	timeLayoutStr := "2006-01-02 15:04:05"
	for index,value :=range devices{
		fmt.Printf("%v-%v\n",index,value)
		meterLastInfo,err:=dbutil.HashGet(utils.DEVICES_STATUS_HASH,value)
		if err !=nil{
			log.Infof("未找到设备:%v",value)
			return
		}

		meterLastStatus := &api.MeterStatus{}
		err =json.Unmarshal([]byte(meterLastInfo), &meterLastStatus)
		if err!=nil{
			log.Info("json反序列化失败")
			continue
		}else{

			if meterLastStatus.Status == 2{

			}else if meterLastStatus.Status == 0{

			}else{

				if meterLastStatus.Protocol == "701"||
					meterLastStatus.Protocol == "702"||
					meterLastStatus.Protocol == "703"||
					meterLastStatus.Protocol == "704"||
					meterLastStatus.Protocol == "705"||
					meterLastStatus.Protocol == "706"{

					lastTime := meterLastStatus.Lasttime
					st, _ := time.ParseInLocation(timeLayoutStr, lastTime,time.Local)
					sub  := time.Now().Sub(st)
					log.Infof("now:%v",time.Now())
					log.Infof("last:%v",st)
					log.Info(sub.Minutes())
					if sub.Minutes()>30{
						meterLastStatus.Status = 2
						// 生成JSON
						jsonStr, err := json.Marshal(meterLastStatus)
						if err != nil {
							log.Errorf("JSON序列化时出现错误, 错误信息：%v", err.Error())
							return
						}
						err = dbutil.HashSet(utils.DEVICES_STATUS_HASH,value,jsonStr)
						if err !=nil{
							log.Errorf("更新状态失败：%v->%v",value,2)
							continue
						}
						dbutil.SetDeviceStatus(meterLastStatus.SiteId,value,2)

					}
				}


			}
		}

	}
}



func CreateTicker(interval int64, doJob func()) {
	// 启动个定时器
	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)

	done := make(chan bool)
	go func() {
		for {
			select {
			case <-done:
				return
			case <-ticker.C:
				doJob()
			}
		}
	}()
}



func main()  {

	////设置日志前缀，主要标记当前日志模块
	//zlog.SetPrefix("MODULE")
	//
	////添加标记位
	//zlog.AddFlag(zlog.BitShortFile | zlog.BitTime)
	//zlog.Stack(" Zinx Stack! ")
	//
	////设置日志写入文件
	//zlog.SetLogFile("./log", "testfile.log")

	defer log.Flush()
	errlog := SetupLogger()

	if errlog !=nil{
		log.Info("日志模块初始化错误：",errlog)
	}

	// 公用的ERROR变量
	var err error

	err  = dbutil.InitMysqlPool()
	if err !=nil{
		log.Info("mysql pool 初始化链接失败")
		return
	}
	defer dbutil.DestroyMysqlPool()


	err = dbutil.InitRedisPool()
	if err !=nil{
		log.Info("redis 初始化链接失败")
		return
	}
	defer dbutil.DestroyRedisPool()


	CreateTicker(60000,checkDevicesTimeOut)
	CreateTicker(5*60000,storageDataToMysql)

	s := znet.NewServer()

	//注册客户端连接建立和丢失函数
	s.SetOnConnStart(OnConnectionAdd)
	s.SetOnConnStop(OnConnectionLost)

	//注册路由
	s.AddRouter(0x00,&api.RegisterApi{})
	s.AddRouter(0x01,&api.BatteryVoltageTemperature{})
	s.AddRouter(0x02,&api.Temperature{})
	s.AddRouter(0x03,&api.BatteryVoltageTemperature{})
	s.AddRouter(0x04,&api.Temperature{})
	s.AddRouter(0x05,&api.BatteryVoltageDoorMagnetismApi{})
	s.AddRouter(0x06,&api.DoorMagnetismApi{})
	s.AddRouter(0x07,&api.BatteryVoltageWaterImmersion{})
	s.AddRouter(0x08,&api.WaterImmersion{})
	s.AddRouter(0x09,&api.BatteryVoltageSmokeSensation{})
	s.AddRouter(0x0A,&api.SmokeSensation{})
	s.AddRouter(0x0B,&api.BatteryVoltageWaterLevel{})
	s.AddRouter(0x0C,&api.WaterLevel{})
	s.AddRouter(0x0D,&api.BatteryVoltageTempAndHum{})
	s.AddRouter(0x0E,&api.TempAndHum{})


	//启动服务
	s.Serve()
}



